#ifndef _GATHER_H_
#define _GATHER_H_

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>

class Gather
{
public:
        enum FlagOrException
        {
                HTTP_GET = 4,
                HTTP_VERSION = 11,
                HTTP_HOST = 6,
                HTTP_NEWLINE = 2,
                HTTP_ACCEPT_ALL = 13,
                HTTP_CONNECTION_CLOSE = 21
        };

public:
    static Gather* getInstance();

    char* collectAPic(const char* request, int& len);

    char* collect(const char* request) throw (int, const char*);

    /**
     * collect data
     * @param request
     * @param receiveLength buffer for the received-data length
     * @return reply string
     */
    char* collect(const char* request, int& receiveLength) throw (int, const char*);

    char* collectPost(const char* request, const char* formContent);

    /**
     * collect data by proxy
     * @param proxyIp
     * @param port
     * @param request
     * @param receiveLength buffer for the received-data length
     * @return reply string
     */
    char* collectByProxy(const char* proxyIp, int port, const char* request, int& receiveLength) throw (int, const char*);

private:
    Gather();
    ~Gather();

	/**
 	 * set the proxy
	 * @param addr proxy id
	 * @param port
	 * @return
	 */
    void httpSet(const char* addr, int addrLength, int port, bool proxy);

	/**
 	 * send the http request string
	 * @param host
	 * @param items
	 * @return return true if sended successfully
 	 */
    void httpSend(const char* host, int hostLength, const char* items, int itemsLength);

    /**
      * return length of  the data received
      * @return return the length
      */
     int httpRecv();

     char* getPos(const char* beginning, int dataLen);

private:
	/**
  	 * set addr struct
	 * @param addr
	 * @param addrLength
	 * @param port
	 * @param sin addr struct to be set
 	 */
 	void setAddr(const char* addr, int addrLength, int port, sockaddr_in& sin);

	/**
	 * conn the target
	 * @param sin
 	 */
	void conn(const sockaddr_in& sin);

	/**
 	 * throw exception if the option passed in is true
	 * @param option
	 * @param exception
	 */
	inline void throwExceptionIfTrue(bool option, int exception) 
	{
		if (option == true)
		{
			throw exception;
		}
	}

    /**
     * parse the input request string
     * @param request
     * @param host
     * @param items
     */
    void requestParse(const char* request, char* host, char* items);

    void reset();

    /**
     * send request, recieve data and close the fd
     * @param proxyIP
     * @param port
     * @param request
     * @return return the recieved data
     */
    char* sendNrecv(const char* proxyIp, int port, const char* request, int& receiveLength);

private:
    int m_fd; /**< socket file description*/
    char* m_data; /**< recived data*/
    char* m_dataPtr; /**< pointer for the data to be pushback*/
};

#endif //_GATHER_H_
